#include "svmClassifyConfig.h"
#include <cstring>

const int extLength = 8;
const char extModel[] = ".output";

void svmClassifyConfig::printHelp() {
	printf("Usage: svmClassify modelFile dataFile [outputFile]\n");
}

char* svmClassifyConfig::readline(FILE *input)
{
	int len;
	
	if(fgets(line,max_line_len,input) == NULL)
		return NULL;

	while(strrchr(line,'\n') == NULL)
	{
		max_line_len *= 2;
		line = (char *) realloc(line,max_line_len);
		len = (int) strlen(line);
		if(fgets(line+len,max_line_len-len,input) == NULL)
			break;
	}
	return line;
}

void svmClassifyConfig::readModel() {
	FILE* model = fopen(modelFilename, "r");
	if (model == NULL) {
		printf("Model File not found\n");
		exit(1);
	}
	
	char cmd[81];
	while(1) {
		fscanf(model,"%80s",cmd);
		if(strcmp(cmd,"svm_type")==0) {
			fscanf(model, "%80s", cmd);
		}
		else if(strcmp(cmd,"kernel_type")==0) {		
			fscanf(model,"%80s",cmd);
			if(strcmp(cmd,kernelTypeString[LINEAR]) == 0)
				kType = LINEAR;
			else if(strcmp(cmd,kernelTypeString[POLYNOMIAL]) == 0)
				kType = POLYNOMIAL;
			else if(strcmp(cmd,kernelTypeString[GAUSSIAN]) == 0)
				kType = GAUSSIAN;
			else if(strcmp(cmd,kernelTypeString[SIGMOID]) == 0)
				kType = SIGMOID;
		}
		else if(strcmp(cmd,"degree")==0)
			fscanf(model,"%f",&degree);
		else if(strcmp(cmd,"gamma")==0)
			fscanf(model,"%f",&gamma);
		else if(strcmp(cmd,"coef0")==0)
			fscanf(model,"%f",&coef);
		else if(strcmp(cmd,"nr_class")==0) {
			fscanf(model,"%d",&nClass);
			if(nClass == 2) nTasks = 1;
			else nTasks = nClass;
		}
		else if(strcmp(cmd,"total_sv")==0)
			fscanf(model,"%d",&nSV);
		else if(strcmp(cmd,"rho")==0) {
			rho = (float*)malloc(sizeof(float)*nTasks);
			for(int i=0;i<nTasks;i++) {
				fscanf(model,"%f",rho+i);
				rho[i] = -rho[i];
				//printf("%f ",rho[i]);
			}
			//putchar(10);
			//fscanf(model,"%f", &b);
			//b = -b;
			//int n = model->nr_class * (model->nr_class-1)/2;
			//model->rho = Malloc(double,n);
			//for(int i=0;i<n;i++)
			//	fscanf(fp,"%lf",&model->rho[i]);
		}
		else if(strcmp(cmd,"label")==0) {
			classLabels = (int*)malloc(sizeof(int)*nClass);
			for(int i=0;i<nClass;i++) {
				fscanf(model,"%d",classLabels+i);
			}
			//fscanf(model,"%f %f",&class1Label,&class2Label);
			//printf("%f %f\n",class1Label, class2Label);
			//int n = model->nr_class;
			//model->label = Malloc(int,n);
			//for(int i=0;i<n;i++)
			//	fscanf(fp,"%d",&model->label[i]);
		}
		else if(strcmp(cmd,"nr_sv")==0) {
			while(1) {
				int c = getc(model);
				if(c==EOF || c=='\n') break;
			}
			//int n = model->nr_class;
			//model->nSV = Malloc(int,n);
			//for(int i=0;i<nClass;i++)
				//fscanf(model,"%*d");
				//fscanf(fp,"%d",&model->nSV[i]);
		}
		else if(strcmp(cmd,"SV")==0) {
			while(1) {
				int c = getc(model);
				if(c==EOF || c=='\n') break;	
			}
			break;
		}
		else {
			fprintf(stderr,"unknown text in model file: [%s]\n",cmd);
			exit(1);
		}
	}

	//int elements =0;
	long pos = ftell(model);

	max_line_len = maxLen;
	line = (char *)malloc(sizeof(char)*max_line_len);

	// TODO 12 rewrite model to indicate max dimension
	while(readline(model)!=NULL) {
		char *p = strtok(line," \t");
		for(int i=1;i<nTasks;i++)
			p = strtok(NULL," \t");
		while(1) {
			p = strtok(NULL," \t");
			if(p == NULL || *p == '\n')
				break;
			int tempDim = atoi(p);
			if(tempDim > SVDim)
				SVDim = tempDim;
			//elements++;
		}
	}
	//elements += nSV;
	
	fseek(model,pos,SEEK_SET);

	alpha = (float*)malloc(sizeof(float)*nSV*nTasks);
	supportVectors = (float*)malloc(sizeof(float)*SVDim*nSV);
	memset((void *)supportVectors,0,sizeof(float)*SVDim*nSV);
	
	//FILE* test = fopen("alpha", "w");

	char * endPtr;
	for(int i=0;i<nSV;i++) {
		//fprintf(stderr,"%d ",i);
		//alpha[i] = 
		readline(model);
		char *p = strtok(line," \t");
		//alpha[i] = (float)strtod(p,&endPtr);
		alpha[i] = (float)strtod(p,&endPtr);
		//fprintf(test,"%g ",alpha[i]);
		//printf("%f ",alpha[i]);
		for(int j=1;j<nTasks;j++) {
			p = strtok(NULL, " \t");
			alpha[i+nSV*j] = (float)strtod(p,&endPtr);
			//fprintf(test,"%g ",alpha[i+nTasks*j]);
			//printf("%f ",alpha[i+nTasks*j]);
		}
		//fprintf(test,"\n");
		//printf("\n");
		//system("PAUSE");

		while(1) {
			char * cIdx = strtok(NULL,":");
			char * cVal = strtok(NULL," \t");

			if(cVal == NULL) break;

			//errno = 0;
			int idx = (int)strtol(cIdx,&endPtr,10);
			//if(endPtr == cIdx || errno !=0 || *endPtr != '\0' || idx <= instMaxIndex)
			//	exitInputError(i+1);
			//else
			//	instMaxIndex = idx;

			//errno = 0;
			supportVectors[(idx-1)*nSV + i] = (float)strtod(cVal,&endPtr);
			//printf("%d:%f ",idx, (float)strtod(cVal,&endPtr));
			//system("PAUSE");
			//if(endPtr == cVal || errno !=0 || (*endPtr != '\0' && !isspace(*endPtr)))
			//	exitInputError(i+1);
			//data[(idx-1)*nPoints+i] = val;
			//transposeData[i*nDimension+idx-1] = val;
		}
	}
	free(line);
	fclose(model);

	//fclose(test);
	//printf("> Problem is %d dimensional\n", SVDim);
	printf("> svmModel found: %d support vectors(%d features)\n", nSV, SVDim);
}

void svmClassifyConfig::parseCommand(const int &argc, const char **&argv) {
	if (argc < 3) {
		printHelp();
		exit(1);
	}
	modelFilename = const_cast<char *>(argv[1]);
	testingFilename = const_cast<char *>(argv[2]);
	if (argc == 4) {
		outputFilename = (char*)malloc(sizeof(char)*(strlen(argv[3])));
		strcpy(outputFilename, argv[3]);
	} else {
		int len = strlen(testingFilename);
		outputFilename = (char*)malloc(sizeof(char)*(len + extLength));
		strcpy(outputFilename, testingFilename);
		char* period = strrchr(outputFilename, '.');
		if (period == NULL)
			period = outputFilename + len;
		strncpy(period, extModel, extLength); 
	}
	printf("> Output file: %s\n", outputFilename);
}

void svmClassifyConfig::checkDimension(int dimension) {
	if (dimension != SVDim) {
		printf("This data isn't compatible with this model,SVdimension:%d;testing data dimension:%d\n",SVDim,dimension);
		exit(3);
	}
}

void svmClassifyConfig::cleanModel() {
	free(rho);
	free(classLabels);
	free(alpha);
	free(supportVectors);
}